import { AssetManager, assetManager, Prefab, SpriteAtlas, SpriteFrame } from "cc";
import { App } from "../../App";
import { TViewConfigResType, ViewId } from "../common/view/IView";
import { IMgr } from "./IMgr";



export class ResMgr implements IMgr {

    init() {

    }

    finit() {

    }

    getBundle(name: string): AssetManager.Bundle {
        return this._bundles.get(name);
    }

    private _bundles: Map<string, AssetManager.Bundle> = new Map();

    /**引用计数 */
    private _bundleMapViewIdRef: Map<AssetManager.Bundle, Set<ViewId>> = new Map();

    /**单纯记录 bundle引用哪些viewId */
    private _bundleMapViewId: Map<AssetManager.Bundle, Set<ViewId>> = new Map();

    get bundles(): Map<string, AssetManager.Bundle> {
        return this._bundles;
    }

    /**
     * 加载bundle
     * @param viewId 
     * @param name 
     * @returns 
     */
    async loadBundle(viewId: ViewId, name: string): Promise<AssetManager.Bundle> {
        const bundle = this._bundles.get(name);
        if (bundle) {
            this.addBundleRelation(viewId, name);
            return Promise.resolve(bundle);
        }
        return new Promise((resolve, reject) => {
            assetManager.loadBundle(name, (err, bundle) => {
                if (err) {
                    return reject(err);
                }

                /** */
                this._bundles.set(name, bundle);

                /** */
                this.addBundleRelation(viewId, name);

                /** */
                this.addBundleViewId(viewId, name);

                resolve(bundle);
            });
        });
    }

    addBundleRelation(viewId: ViewId, bundleName: string): void {

        const root = App.ins.viewMgr.getRootViewId(viewId);
        if (root != viewId) {
            return;
        }

        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            return;
        }
        let set = this._bundleMapViewIdRef.get(bundle);
        if (!set) {
            set = this._bundleMapViewIdRef.set(bundle, new Set()).get(bundle)
        }
        set.add(viewId);

        // console.log("  addBundleRelation set size ", set.size);

    }

    removeBundleRelation(viewId: ViewId, bundleName: string): void {

        const root = App.ins.viewMgr.getRootViewId(viewId);
        if (root != viewId) {
            return;
        }

        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            return;
        }
        let set = this._bundleMapViewIdRef.get(bundle);
        if (!set) {
            return;
        }
        set.delete(viewId);

        // console.log("  removeBundleRelation set size ", set.size);

        /** todo 应该要延时释放 */
        if (set.size <= 0) {
            this.releaseAllByBundle(bundleName);
        }
    }

    addBundleViewId(viewId: ViewId, bundleName: string): void {

        const root = App.ins.viewMgr.getRootViewId(viewId);
        if (root != viewId) {
            return;
        }

        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            return;
        }
        let set = this._bundleMapViewId.get(bundle);
        if (!set) {
            set = this._bundleMapViewId.set(bundle, new Set()).get(bundle)
        }
        set.add(viewId);

    }

    /**
     * 根据bundle名字释放bundle资源
     * @param bundleName 
     */
    private releaseAllByBundle(bundleName: string): void {
        const bundle = this._bundles.get(bundleName);

        if (bundle) {
            const set = this._bundleMapViewId.get(bundle);
            if (set) {
                const viewMgr = App.ins.viewMgr;
                set.forEach((viewId: ViewId) => {
                    const ctrl = viewMgr.getCtrl(viewId);
                    ctrl.destroy();
                })
            }
        }

        bundle?.releaseAll();
    }

    /**
     * 加载散图
     * @param bundleName 
     * @param res 
     */
    async loadSinglePicResByBundle(bundleName: string, resName: string): Promise<SpriteFrame> {
        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            /**必须要先loadBundle */
            return Promise.reject(`bundle not found, bundle name .. ` + bundleName)
        }

        const res = bundle.get(resName) as SpriteFrame;
        if (res) {
            return Promise.resolve(res);
        }

        return new Promise((resolve, reject) => {
            bundle.load(resName, SpriteFrame, (err, data: SpriteFrame) => {
                if (err) {
                    return reject(err);
                }
                data.addRef && data.addRef();
                resolve(data);
            })
        })
    }

    /**
     * 加载图集
     * @param bundleName 
     * @param atlasPath 
     * @param type 
     */
    async loadAtlasByBundle(bundleName: string, atlasPath: string): Promise<SpriteAtlas> {
        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            /**必须要先loadBundle */
            return Promise.reject(`bundle not found, bundle name .. ` + bundleName)
        }
        if (!atlasPath) {
            return Promise.resolve(null)
        }

        const atlas = bundle.get(atlasPath) as SpriteAtlas;
        if (atlas) {
            return Promise.resolve(atlas);
        }

        return new Promise((resolve, reject) => {
            bundle.load(atlasPath, SpriteAtlas, (err, data: SpriteAtlas) => {
                if (err) {
                    return reject(err);
                }
                data.addRef && data.addRef();
                resolve(data);
            })
        })
    }

    // async loadAtlasArrByBundle(bundleName: string, atlasNameArr: string[]): Promise<any> {
    //     const total = atlasNameArr.length;
    //     if (!total) {
    //         return Promise.resolve(null);
    //     }
    //     let count = 0;
    //     return new Promise((resolve, reject) => {
    //         for (const atlasName of atlasNameArr) {
    //             this.loadAtlasByBundle(bundleName, atlasName).then(() => {
    //                 count++;
    //                 if (count >= total) {
    //                     resolve(null);
    //                 }
    //             }).catch((reason) => {
    //                 reject(reason);
    //             })
    //         }
    //     })
    // }

    /**
     * 加载预制体
     * @param bundleName 
     * @param prefabPath 
     * @returns 
     */
    async loadPrefab(bundleName: string, prefabPath: string): Promise<Prefab> {
        const bundle = this._bundles.get(bundleName);
        if (!bundle) {
            return Promise.reject(`bundle not found, bundle name .. ` + bundleName)
        }

        const res = bundle.get(prefabPath) as Prefab;
        if (res) {
            return Promise.resolve(res);
        }
        return new Promise((resolve, reject) => {
            bundle.load(prefabPath, (err, data: Prefab) => {
                if (err) {
                    return reject(err);
                }
                data.addRef && data.addRef();
                resolve(data);
            })
        })

    }

    async loadResArr(bundleName: string, arr: TViewConfigResType[]): Promise<any> {
        if (!arr || arr.length <= 0) {
            return Promise.resolve();
        }
        const oneRes = arr.shift();
        switch (oneRes.type) {
            case SpriteAtlas: {
                this.loadAtlasByBundle(bundleName, oneRes.path).then(() => {
                    return this.loadResArr(bundleName, arr);
                });
                break;
            }
        }
    }

}